package gttp.nspa.server.adm.rpc;

import gttp.nspa.client.adm.rpc.IBillingService;
import gttp.nspa.server.dao.DAJ;
import gttp.nspa.server.dao.DAJs;
import gttp.nspa.server.dao.DAO;
import gttp.nspa.server.dao.DAOs;
import gttp.nspa.server.dao.FilterBuilder;
import gttp.nspa.shared.om.Billing;
import gttp.nspa.shared.om.Billing.Status;
import gttp.nspa.shared.om.Customer;
import gttp.nspa.shared.om.IOrder;
import gttp.nspa.shared.om.Massa;
import gttp.nspa.shared.om.MassaOrder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class BillingService implements IBillingService {

    protected final DAO<Billing>    billDAO;
    protected final DAO<Customer>   custDAO;
    protected final DAO<MassaOrder> msodDAO;
    protected final DAJ<Massa>      massDAJ;

    public BillingService() {
        billDAO = DAOs.billing;
        custDAO = DAOs.customer;
        msodDAO = DAOs.massaOrder;
        massDAJ = DAJs.massa;
    }

    public Billing load(long id) {
        return billDAO.load(id);
    }

    public void save(Billing b) {
        billDAO.save(b);
    }

    public void delete(long id) {
        billDAO.delete(id);
    }

    public void delete(Long[] ids) {
        billDAO.delete(Arrays.asList(ids));
    }

    protected FilterBuilder buildFilter(Long beginFrom,
                                        Long beginTo,
                                        Long endFrom,
                                        Long endTo,
                                        String alias,
                                        String customer,
                                        String locker,
                                        Status status) {
        FilterBuilder fb = new FilterBuilder();
        if (beginFrom != null) {
            fb.gte("time", beginFrom);
        }
        if (beginTo != null) {
            fb.lte("time", beginTo);
        }
        if (endFrom != null) {
            fb.gte("timeEnd", endFrom);
        }
        if (endTo != null) {
            fb.lte("timeEnd", endTo);
        }
        if (alias != null) {
            fb.eq("alias", alias);
        }
        if (customer != null) {
            fb.eq("customer.name", customer);
        }
        if (locker != null) {
            fb.eq("locker", locker);
        }
        if (status != null) {
            fb.eq("status", status);
        }
        return fb;
    }

    public List<Billing> listBy(Long beginFrom,
                                Long beginTo,
                                Long endFrom,
                                Long endTo,
                                String alias,
                                String customer,
                                String locker,
                                Status status,
                                int offset,
                                int limit,
                                String[] orders) {
        FilterBuilder fb = buildFilter(beginFrom, beginTo, endFrom, endTo, alias, customer, locker, status);
        Iterator<Billing> it = billDAO.load(offset, limit, orders, fb.build());
        List<Billing> list = new ArrayList<>();
        while (it.hasNext()) {
            list.add(it.next());
        }
        return list;
    }

    public Billing book(String cashier, long custId) {
        Billing billing = null;
        Customer cust = custDAO.load(custId);
        if (cust != null) {
            billing = new Billing(cashier, cust);
            billDAO.save(billing);
            return billing;
        }
        return billing;
    }

    public Billing book(String cashier, String custAlias) {
        Billing billing = new Billing(cashier, custAlias);
        billDAO.save(billing);
        return billing;
    }

    public Billing open(long billId, String locker) {
        Billing billing = billDAO.load(billId);
        if (billing != null) {
            billing.open(locker);
        }
        return billing;
    }

    public Billing open(String cashier, long custId, String locker) {
        Billing billing = null;
        Customer cust = custDAO.load(custId);
        if (cust != null) {
            billing = new Billing(cashier, cust);
            billing.open(locker);
            billDAO.save(billing);
            return billing;
        }
        return billing;
    }

    public Billing open(String cashier, String custAlias, String locker) {
        Billing billing = new Billing(cashier, custAlias);
        billing.open(locker);
        billDAO.save(billing);
        return billing;
    }

    public boolean cancelOrder(long billId, long orderId, String reason) {
        Billing billing = billDAO.load(billId);
        if (billing != null && billing.getStatus() == Status.OPENING) {
            IOrder ord = billing.cancelOrder(orderId, reason);
            if (ord instanceof MassaOrder) {
                msodDAO.save((MassaOrder) ord);
                return true;
            }
        }
        return false;
    }

    public boolean serveOrder(long billId, long orderId) {
        Billing billing = billDAO.load(billId);
        if (billing != null && billing.getStatus() == Status.OPENING) {
            IOrder ord = billing.serveOrder(orderId);
            if (ord instanceof MassaOrder) {
                msodDAO.save((MassaOrder) ord);
                return true;
            }
        }
        return false;
    }

    public boolean serveOrderDone(long billId, long orderId) {
        Billing billing = billDAO.load(billId);
        if (billing != null && billing.getStatus() == Status.OPENING) {
            IOrder ord = billing.serveOrderDone(orderId);
            if (ord instanceof MassaOrder) {
                msodDAO.save((MassaOrder) ord);
                return true;
            }
        }
        return false;
    }

    public MassaOrder orderMassa(long billId, String therapist, String massa) {
        Billing billing = billDAO.load(billId);
        if (billing != null && billing.getStatus() == Status.OPENING) {
            MassaOrder mo;
            Massa mass = massDAJ.get(massa);
            if (mass == null)
                mo = new MassaOrder(therapist);
            else
                mo = new MassaOrder(therapist, massa, mass.getPrice());
            billing.addOrder(mo);
            billDAO.save(billing);
            return mo;
        }
        return null;
    }

    public void serveMassa(long billId) {
        Billing billing = billDAO.load(billId);
        if (billing != null && billing.getStatus() == Status.OPENING) {
            List<IOrder> ords = billing.getOrders();
            for (IOrder ord : ords) {
                if (ord instanceof MassaOrder) {
                    ord.serve();
                    msodDAO.save((MassaOrder) ord);
                }
            }
        }
    }

}
